package com.guanghua.brick.db;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.guanghua.brick.BrickConstant;
import com.guanghua.brick.util.PatternListener;
import com.guanghua.brick.util.StringUtil;

/**
 * 一个内部使用的查询sql解析类
 * 通过pageinfo, orderinfo, sql, filterinfo的传入,编译出需要的sql
 * 转换成分页sql和计算总记录数的sql，供执行得出结果
 * @author leeon
 */
public class SQLCompiler {
	
	private static final Log logger = LogFactory.getLog(SQLCompiler.class);
	
	private PageInfo pager = null;
	private OrderInfo order = null;
	private Map<String, Object> filter = null;
	
	private String sql = null;
	
	private List<Object> param = null;
	
	private SQLCompiler() {};
	
	public SQLCompiler(String sql, PageInfo pager, OrderInfo order, Map<String, Object> filter) {
		//init param
		this.sql = sql;
		this.pager = pager;
		this.order = order;
		this.filter = filter;
		
		logger.debug("before compiler sql:" + sql);
		logger.debug("before complier filter:" + filter);
		//处理过滤条件参数
		if (this.filter != null) {
			//参数列表
			this.param = new ArrayList<Object>();
			this.sql = StringUtil.replacePattern(this.sql, new PatternListener() {
				
				//解析出${}段,然后进行filter解析
				public String onPatternMatch(String source) {
					logger.trace("compiler sql section source:" + source);
					return SQLCompiler.this.filterSection(source);
				}
				
			});
		}
		logger.debug("after compiler sql:" + this.sql);
		logger.debug("after compiler sql param:" + this.param);
	}
	
	
	//获取分页查询用的sql，过滤条件已经解析成?传参形式
	public String getPageSql() {
		if (this.pager != null) {
			ISQLPagerSection ps = BrickConstant.getSQLPagerSection();
			return ps.transformToPageSQL(
					this.sql + ((this.order != null)?this.order.getOrder():""),  this.pager);
		} else {
			return this.sql + ((this.order != null)?this.order.getOrder():"");
		}
	}
	
	//获取记录总数查询用的sql，过滤条件已经解析成?传参形式
	public String getCountSql() {
		//需要进行计数查询
		if (this.pager != null && this.pager.getCountType() == PageInfo.COUNT_FIRST_TIME && this.pager.getRowCount() == 0) {
			ISQLPagerSection ps = BrickConstant.getSQLPagerSection();
			return ps.transformToCountSQL(this.sql);
		//需要进行计数查询
		} else if (this.pager != null && this.pager.getCountType() == PageInfo.COUNT_EVERY_TIME) {
			ISQLPagerSection ps = BrickConstant.getSQLPagerSection();
			return ps.transformToCountSQL(this.sql);
		} else {
			return null;
		}
	}

	//获取传参用的参数列表
	public List<Object> getParam() {
		return this.param;
	}
	
	//获取编译后的SQL
	public String getSql() {
		return this.sql;
	}
	
	/**
	 * 将一段filter section 进行解析，转化为连接符号，属性，操作符号，属性值
	 * @param section
	 * @return
	 */
	private String filterSection(String section) {
		ISQLFilterSection fs = BrickConstant.getSQLFilterSection();
		char[] c = section.toCharArray();
		
		
		StringBuffer t = new StringBuffer();//临时栈
		int tag = -1;//标志，0表示空格区，1表示变量区，2表示字符串区
		ArrayList<String> l = new ArrayList<String>();//记录结果
		
		for (int i = 0; i < c.length; i++) {
			//空格
			if (c[i] == ' ') {
				if (tag == 1) {
					l.add(t.toString());
					t.setLength(0);
				} else if (tag == 2) {
					l.add(t.toString());
					t.setLength(0);
				}
				tag = 0;
			//变量形式
			} else if ((c[i] >= 'a' && c[i] <= 'z') || 
						(c[i] >= 'A' && c[i] <= 'Z') || 
						(c[i] >= '0' && c[i] <= '9') || 
						(c[i] == '_') || (c[i] == ':')|| (c[i] == '.')) {
				if (tag == 2) {
					l.add(t.toString());
					t.setLength(0);
				}
				tag = 1;
				t.append(c[i]);
			//符号形式
			} else {
				if (tag == 1) {
					l.add(t.toString());
					t.setLength(0);
				}
				tag = 2;
				t.append(c[i]);
			}
		}
		if (t.length() != 0) l.add(t.toString());
		logger.trace("filter section:" + section);
		logger.trace("filter section parse result:" + l);
		
		if (l.size() != 4) {
			logger.warn("parse filter section wrong, no valid format:" + section);
			return null;
		} else {
			String s3 = l.get(3);
			s3 = (s3.startsWith(":"))?s3.substring(1):s3;
			return fs.onFilterSection(l.get(0), l.get(1), l.get(2), s3, this.filter, this.param);
		}
	}
	
//	public static void main(String[] arg) {
//		Map<String, Object> queryFilter = new HashMap<String, Object>();
//		queryFilter.put("name", "leeon");
//		queryFilter.put("grade", "1,2,3");
//		queryFilter.put("sex", "1");
//		queryFilter.put("birthday", "2007-09-09");
//		String sql = "select * from student s where 1 = 1 " +
//				"${and s.name like :name} " +
//				"${and s.grade in :grade} " +
//				"${and s.sex = :sex} " +
//				"${and s.birthday deq :birthday} order by s.name";
//		SQLCompiler c = new SQLCompiler(sql, null, null, queryFilter);
//	}
}
